home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 20 code / Scripting the Finder / Finder Tricks / DialogUtilities.cp < prev    next >
Encoding:
Text File  |  1994-10-04  |  32.3 KB  |  1,183 lines  |  [TEXT/MMCC]

  1. /*================================================================================
  2.     DialogUtilities.c
  3.     
  4.     circa 1991 by Greg Anderson
  5.     greggor@apple.com
  6.     
  7.     This file contains various dialog box utility routines
  8. ================================================================================*/
  9. #include "DialogUtilities.h"
  10.  
  11. #include <Types.h>
  12. #include <Errors.h>
  13. #include <Memory.h>
  14. #include <Resources.h>
  15. #include <Quickdraw.h>
  16. #include <Controls.h>
  17. #include <Dialogs.h>
  18. #include <MixedMode.h>
  19.  
  20. #if USESROUTINEDESCRIPTORS
  21.     RoutineDescriptor gDrawDottedLineProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawDottedLineProc);
  22.     RoutineDescriptor gDrawFrameRectProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawFrameRectProc);
  23.     RoutineDescriptor gDrawDefaultProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawDefaultProc);
  24.     RoutineDescriptor gDrawActiveItemProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawActiveItemProc);
  25.     RoutineDescriptor gDrawGreyTransformProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawGreyTransformProc);
  26.     RoutineDescriptor gCutPasteFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterProcInfo, CutPasteFilter);
  27. #endif
  28.  
  29. //----------------------------------------------------------------------------------------
  30. // SimpleBox: 
  31. //
  32. // Display a dialog
  33. //----------------------------------------------------------------------------------------
  34. void SimpleBox(short id)
  35. {
  36.     DialogPtr        dlog;
  37.     short            itemHit;
  38.  
  39.     dlog = GetNewDialog( id, (Ptr)0L, (WindowPtr)-1L);
  40.  
  41.     if( dlog != nil )
  42.     {
  43.         SetPort( dlog );
  44.         SelectWindow(dlog);
  45.         InstallDefaultOutline( dlog, 1 );
  46.         CenterAndShowDialog(dlog);
  47.         
  48.         //
  49.         // Wait for user to click "Okay"
  50.         //
  51.         do
  52.         {
  53. #if USESROUTINEDESCRIPTORS
  54.                 ModalDialog((ModalFilterUPP) &gCutPasteFilterRD, &itemHit);
  55. #else
  56.                 ModalDialog((ModalFilterUPP) CutPasteFilter, &itemHit);
  57. #endif
  58.         } while( itemHit != 1 );
  59.         DisposDialog(dlog);
  60.     }
  61.     else
  62.     {
  63.         DebugStr( "\pCouldn't show simple dialog" );
  64.     }
  65. } // SimpleBox 
  66.  
  67. //----------------------------------------------------------------------------------------
  68. // MessageBox: 
  69. //
  70. // Display a message
  71. //----------------------------------------------------------------------------------------
  72. void MessageBox(short id, Str255 pstr)
  73. {
  74.     DialogPtr        dlog;
  75.     short            itemHit;
  76.  
  77.     dlog = GetNewDialog( id, (Ptr)0L, (WindowPtr)-1L);
  78.  
  79.     if( dlog != nil )
  80.     {
  81.         SetPort( dlog );
  82.         ParamText( pstr, nil, nil, nil );
  83.         SelectWindow(dlog);
  84.         InstallDefaultOutline( dlog, 1 );
  85.         CenterAndShowDialog(dlog);
  86.         
  87.         //
  88.         // Wait for user to click "Okay"
  89.         //
  90.         do
  91.         {
  92. #if USESROUTINEDESCRIPTORS
  93.                 ModalDialog((ModalFilterUPP) &gCutPasteFilterRD, &itemHit);
  94. #else
  95.                 ModalDialog((ModalFilterUPP) CutPasteFilter, &itemHit);
  96. #endif
  97.         } while( itemHit != 1 );
  98.         DisposDialog(dlog);
  99.     }
  100.     else
  101.     {
  102.         DebugStr( pstr );
  103.     }
  104. } // MessageBox 
  105.  
  106. //----------------------------------------------------------------------------------------
  107. // CenterAndShowDialog: 
  108. //
  109. //    Center the specified dialog box & show it
  110. //    
  111. //    This code centers the dialog box on the main monitor (the one
  112. //    with the menu bar) such that 1/3rd of the empty space left on
  113. //    that screen is above the dialog and 2/3rds of it is below the
  114. //    dialog
  115. //
  116. //    Note:
  117. //    
  118. //    This routine looks at MBarHeight to correctly calculate the
  119. //    horizontal position of the dialog box.  Accessing low memory
  120. //    globals is generally an evil thing to do, but in this case
  121. //    there is no good alternative.
  122. //----------------------------------------------------------------------------------------
  123. void CenterAndShowDialog(DialogPtr dlog)
  124. {
  125.     short            menuHeight;
  126.     short            dlogWidth;
  127.     short            dlogHeight;
  128.     short            scrnWidth;
  129.     short            scrnHeight;
  130.     short            newDlogX;
  131.     short            newDlogY;
  132.     
  133.     //
  134.     // What is the height of the menu bar (in pixels)?
  135.     //
  136.     menuHeight = GetMBarHeight();
  137.     
  138.     //
  139.     // Calculate the size of the dialog box and the main screen
  140.     // (without the menu bar)
  141.     //
  142.     dlogWidth    = (dlog->portRect.right - dlog->portRect.left);
  143.     dlogHeight    = (dlog->portRect.bottom - dlog->portRect.top);
  144.     scrnWidth    = (qd.screenBits.bounds.right - qd.screenBits.bounds.left);
  145.     scrnHeight    = (qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) - menuHeight;
  146.     
  147.     //
  148.     // Quick check: don't leave any empty space if the dialog is
  149.     // too large to fit on the main screen.  This sanity check
  150.     // really should not be necessary, though, as all dialog boxes
  151.     // should fit on 9" screens
  152.     //
  153.     if( dlogHeight > scrnHeight)
  154.         dlogHeight = scrnHeight;
  155.         
  156.     //
  157.     // Calculate the menu's new location
  158.     //
  159.     newDlogX = qd.screenBits.bounds.left + (scrnWidth - dlogWidth) / 2;
  160.     newDlogY = qd.screenBits.bounds.top + menuHeight + (scrnHeight - dlogHeight) / 3;
  161.     
  162.     //
  163.     // Move the dialog and show it
  164.     //
  165.     MoveWindow(dlog,newDlogX,newDlogY,false);
  166.     ShowWindow(dlog);
  167. } // CenterAndShowDialog 
  168.  
  169. //----------------------------------------------------------------------------------------
  170. // AddNewUserItem:
  171. //
  172. //    Creates a new useritem in the specified dialog box & returns
  173. //    its item number
  174. //----------------------------------------------------------------------------------------
  175. short AddNewUserItem( DialogPtr dlog )
  176. {
  177.     DialogPeek        theDialog        = (DialogPeek)dlog;
  178.     short**            itemHandle        = (short**)theDialog->items;
  179.     short            nItems            = **itemHandle + 1;
  180.     short            newItem            = 0;
  181.     DITLitem*        ditlPtr;
  182.     Size            itemHandleSize;
  183.     
  184.     itemHandleSize = GetHandleSize( (Handle)itemHandle );
  185.     SetHandleSize( (Handle)itemHandle, itemHandleSize + sizeof(DITLitem) );
  186.     if( MemError() == noErr )
  187.     {
  188.         //
  189.         // We dereference the (potentially) unlocked itemHandle
  190.         // here; don't do any memory-moving calls until we've
  191.         // initialized the new DITL item
  192.         //
  193.         ditlPtr = (DITLitem*) ( (*itemHandle) + (itemHandleSize / sizeof(short)) );
  194.         
  195.         //
  196.         // Fill in the new fields
  197.         //
  198.         ditlPtr->placeholder = 0;
  199.         ditlPtr->itemType = userItem;
  200.         ditlPtr->extraLength = 0;
  201.         
  202.         //
  203.         // Remember / record the new number of items
  204.         //
  205.         newItem = nItems + 1;
  206.         **itemHandle = newItem - 1;
  207.     }
  208.     
  209.     return newItem;
  210. } // AddNewUserItem 
  211.  
  212. //----------------------------------------------------------------------------------------
  213. // DrawDottedLineProc: 
  214. //
  215. // Draw a dotted line; install as the draw proc for a user item.
  216. //----------------------------------------------------------------------------------------
  217. pascal void DrawDottedLineProc(DialogPtr dlog, short item)
  218. {
  219.     short                type;
  220.     Handle                itemHandle;
  221.     Rect                box;
  222.     PenState            saveState;
  223.     Point                lineStart;
  224.     Point                lineEnd;
  225.     
  226.     //
  227.     // Save the drawing mode before doing anything with
  228.     // the pen
  229.     //
  230.     GetPenState( &saveState );
  231.     
  232.     //
  233.     // Get the bounding box of the userItem & set lineStart
  234.     // to the upper left corner and lineEnd to the lower right
  235.     // corner of the bounding rectangle
  236.     //
  237.     GetDItem(dlog, item, &type, (Handle*)&itemHandle, &box);
  238.     lineStart.h = box.left;
  239.     lineStart.v = box.top;
  240.     lineEnd.h = box.right;
  241.     lineEnd.v = box.bottom;
  242.     
  243.     //
  244.     // The line is always drawn along the longer edge
  245.     //
  246.     if( (lineEnd.h - lineStart.h) > (lineEnd.v - lineStart.v) )
  247.         lineEnd.v = lineStart.v;
  248.     else
  249.         lineEnd.h = lineStart.h;
  250.         
  251.     //
  252.     // Set the pen mode and draw the line
  253.     //
  254.     PenNormal();
  255.     PenPat(&qd.gray);
  256.     MoveTo( lineStart.h, lineStart.v );
  257.     LineTo( lineEnd.h, lineEnd.v );
  258.     
  259.     //
  260.     // Restore the pen state
  261.     //
  262.     SetPenState( &saveState );
  263. } // DrawDottedLineProc 
  264.  
  265. //----------------------------------------------------------------------------------------
  266. // SetUserItemToDottedLine: 
  267. //
  268. // Make the given userItem a dotted line
  269. //----------------------------------------------------------------------------------------
  270. void SetUserItemToDottedLine( DialogPtr dlog, short whichItem )
  271. {
  272.     short            type;
  273.     Handle            itemHandle;
  274.     Rect            box;
  275.     
  276.     GetDItem(dlog,whichItem,&type,&itemHandle,&box);
  277. #if USESROUTINEDESCRIPTORS
  278.     SetDItem(dlog,whichItem,type,(Handle)&gDrawDottedLineProcRD,&box);
  279. #else
  280.     SetDItem(dlog,whichItem,type,(Handle)DrawDottedLineProc,&box);
  281. #endif
  282. } // SetUserItemToDottedLine 
  283.  
  284. //----------------------------------------------------------------------------------------
  285. // DrawFrameRectProc: 
  286. //
  287. // Draw a frame around the specified userItem
  288. //----------------------------------------------------------------------------------------
  289. pascal void DrawFrameRectProc(DialogPtr dlog, short item)
  290. {
  291.     short                type;
  292.     Handle                itemHandle;
  293.     Rect                box;
  294.     PenState            saveState;
  295.     
  296.     //
  297.     // Save the drawing mode before doing anything with
  298.     // the pen
  299.     //
  300.     GetPenState( &saveState );
  301.     
  302.     //
  303.     // Get the bounding box of the userItem
  304.     //
  305.     GetDItem(dlog, item, &type, (Handle*)&itemHandle, &box);
  306.     
  307.     //
  308.     // Set the pen mode and draw the box
  309.     //
  310.     PenNormal();
  311.     FrameRect( &box );
  312.     
  313.     //
  314.     // Restore the pen state
  315.     //
  316.     SetPenState( &saveState );
  317. } // DrawFrameRectProc 
  318.  
  319. //----------------------------------------------------------------------------------------
  320. // SetUserItemToFrameRect: 
  321. //
  322. // Make the given user item a simple frame
  323. //----------------------------------------------------------------------------------------
  324. void SetUserItemToFrameRect( DialogPtr dlog, short whichItem )
  325. {
  326.     short            type;
  327.     Handle            itemHandle;
  328.     Rect            box;
  329.     
  330.     GetDItem(dlog,whichItem,&type,&itemHandle,&box);
  331. #if USESROUTINEDESCRIPTORS
  332.     SetDItem(dlog,whichItem,type,(Handle)&gDrawFrameRectProcRD,&box);
  333. #else
  334.     SetDItem(dlog,whichItem,type,(Handle)DrawFrameRectProc,&box);
  335. #endif
  336. } // SetUserItemToFrameRect 
  337.  
  338. //----------------------------------------------------------------------------------------
  339. // DrawDefaultProc:
  340. //
  341. //    Draw the thick rounded rectangle around the default button
  342. //
  343. //    This routine uses Keith Rollin's algorithm, as presented in the
  344. //    USENET Guide to Programming the Macintosh.  I have modified the
  345. //    basic algorithm only slightly--I add two to the calculated
  346. //    'buttonOval' value.  This gets better results, particularly for
  347. //    buttons of the default size (18 points).
  348. //----------------------------------------------------------------------------------------
  349. pascal void DrawDefaultProc(DialogPtr dlog, short item)
  350. {
  351.     short                defaultButton;
  352.     
  353.     //
  354.     // Don't call GetDItem if the default button # has a strange value
  355.     //
  356.     defaultButton = ((DialogPeek)dlog)->aDefItem;
  357.     if( defaultButton > 0 )
  358.     {
  359.         short                type;
  360.         Handle                userHandle;
  361.         Rect                outlineBox;
  362.  
  363.         //
  364.         // Only draw the bold outline around the default button
  365.         // if it really is a button
  366.         //
  367.         GetDItem(dlog, defaultButton, &type, &userHandle, &outlineBox);
  368.         if( (type & (ctrlItem + btnCtrl)) == ctrlItem + btnCtrl )
  369.         {
  370.             PenState            saveState;
  371.             short                buttonOval;
  372.  
  373.             GetPenState( &saveState );
  374.             InsetRect(&outlineBox,-4,-4);
  375.             
  376.             //
  377.             // We want to draw the thick line with a normal
  378.             // pen pattern that is 3 pixels wide
  379.             //
  380.             PenNormal();
  381.             PenSize(3,3);
  382.             PenMode(srcCopy);
  383.             
  384.             //
  385.             // If the button we are outlining is disabled,
  386.             // draw the outline with a gray pattern.
  387.             //
  388.             if( !DialogItemEnabled(dlog, defaultButton ) )
  389.             {
  390.                 PenPat(&qd.gray);
  391.             }
  392.             
  393.             //
  394.             // Calculate the curvature to use and draw the thick line
  395.             //
  396.             buttonOval = 2 + (outlineBox.bottom - outlineBox.top) / 2;
  397.             FrameRoundRect(&outlineBox,buttonOval,buttonOval);
  398.             
  399.             SetPenState( &saveState );
  400.         }
  401.     }
  402. } // DrawDefaultProc 
  403.  
  404. //----------------------------------------------------------------------------------------
  405. // InstallDefaultOutline: 
  406. //
  407. //    This function creates a useritem around the default button &
  408. //    installs a drawing proc that draws the default border around it.
  409. //    
  410. //    If you want a button other than button #1 to act as the default
  411. //    button, don't forget to supply your own filterProc that
  412. //    translates Return to the correct item number.  If you use the
  413. //    CutPasteFilter implemented in this file, Return and Enter will
  414. //    be translated to be equivalent to clicking on the button that
  415. //    has the default outline around it.
  416. //----------------------------------------------------------------------------------------
  417. short InstallDefaultOutline(DialogPtr dlog, short button)
  418. {
  419.     short            userItem;
  420.     short            type;
  421.     Handle            item;
  422.     Rect            box;
  423.     Rect            userBox;
  424.     
  425.     ((DialogPeek)dlog)->aDefItem = button;
  426.     userItem = AddNewUserItem( dlog );
  427.     if( userItem > 0 )
  428.     {
  429.         GetDItem(dlog, button, &type, &item, &box);
  430.         InsetRect(&box,-4,-4);
  431.         GetDItem(dlog, userItem, &type, &item, &userBox);
  432. #if USESROUTINEDESCRIPTORS
  433.         SetDItem(dlog,userItem,type,(Handle)&gDrawDefaultProcRD,&userBox);
  434. #else
  435.         SetDItem(dlog,userItem,type,(Handle)DrawDefaultProc,&userBox);
  436. #endif
  437.     }
  438.     
  439.     return userItem;
  440. } // InstallDefaultOutline 
  441.  
  442. //----------------------------------------------------------------------------------------
  443. // DrawActiveItemProc: 
  444. //
  445. //    Draw the thick square rectangle around the dialog item that accepts
  446. //    keyboard input (see the System 7 Chooser for an example).
  447. //----------------------------------------------------------------------------------------
  448. pascal void DrawActiveItemProc(DialogPtr dlog, short item)
  449. {
  450.     short            type;
  451.     Handle            itemHandle;
  452.     Rect            box;
  453.     PenState        saveState;
  454.     
  455.     GetPenState( &saveState );
  456.     GetDItem(dlog, item, &type, &itemHandle, &box);
  457.     PenNormal();
  458.     PenSize(2,2);
  459.     FrameRect(&box);
  460.     SetPenState( &saveState );
  461. } // DrawActiveItemProc 
  462.  
  463. //----------------------------------------------------------------------------------------
  464. // InstallActiveItemOutline: 
  465. //
  466. //    This function creates a useritem around the specified button & installs
  467. //    a drawing proc that draws the default border around it.
  468. //----------------------------------------------------------------------------------------
  469. short InstallActiveItemOutline(DialogPtr dlog, short button)
  470. {
  471.     short            userItem;
  472.     short            type;
  473.     Handle            item;
  474.     Rect            box;
  475.     Rect            userBox;
  476.     
  477.     userItem = AddNewUserItem( dlog );
  478.     if( userItem > 0 )
  479.     {
  480.         GetDItem(dlog, button, &type, &item, &box);
  481.         InsetRect(&box,-4,-4);
  482.         GetDItem(dlog, userItem, &type, &item, &userBox);
  483. #if USESROUTINEDESCRIPTORS
  484.         SetDItem(dlog,userItem,type,(Handle)&gDrawActiveItemProcRD,&userBox);
  485. #else
  486.         SetDItem(dlog,userItem,type,(Handle)DrawActiveItemProc,&userBox);
  487. #endif
  488.     }
  489.     
  490.     return userItem;
  491. } // InstallActiveItemOutline 
  492.  
  493. //----------------------------------------------------------------------------------------
  494. // DrawGreyTransformProc: 
  495. //
  496. //    Draw a grey transform to shade out a disabled control; this is most
  497. //    useful in conjunction with editText items, which do not normally draw
  498. //    with a disabled transform.
  499. //
  500. //    This function ASSUMES that the item after it is the one it should
  501. //    check for enabled/disabledness.
  502. //----------------------------------------------------------------------------------------
  503. pascal void DrawGreyTransformProc(DialogPtr dlog, short item)
  504. {
  505.     PenState        saveState;
  506.     short            userItem;
  507.     short            type;
  508.     Handle            itemHandle;
  509.     Rect            userBox;
  510.     
  511.     //
  512.     // Assume that the item before us is the one
  513.     // that we are obscuring; check it for being
  514.     // disabled
  515.     //
  516.     GetDItem(dlog, item - 1, &type, &itemHandle, &userBox);
  517.     if(type & itemDisable)
  518.     {
  519.         GetDItem(dlog, item, &type, &itemHandle, &userBox);
  520.     
  521.         GetPenState( &saveState );
  522.         PenNormal();
  523.         PenPat(&qd.gray);
  524.         PenMode(srcBic);
  525.         PaintRect(&userBox);
  526.         SetPenState( &saveState );
  527.     }
  528. } // DrawGreyTransformProc 
  529.  
  530. //----------------------------------------------------------------------------------------
  531. // InstallGreyTransform: 
  532. //
  533. //    Install 'DrawGreyTransformProc' around the specified user item.
  534. //----------------------------------------------------------------------------------------
  535. short InstallGreyTransform(DialogPtr dlog, short userItem)
  536. {
  537.     short            type;
  538.     Handle            item;
  539.     Rect            userBox;
  540.  
  541.     
  542.     GetDItem(dlog, userItem, &type, &item, &userBox);
  543. #if USESROUTINEDESCRIPTORS
  544.     SetDItem(dlog,userItem,type,(Handle)&gDrawGreyTransformProcRD,&userBox);
  545. #else
  546.     SetDItem(dlog,userItem,type,(Handle)DrawGreyTransformProc,&userBox);
  547. #endif
  548.     
  549.     return userItem;
  550. } // InstallGreyTransform 
  551.  
  552. //----------------------------------------------------------------------------------------
  553. // MoveOutline: 
  554. //    
  555. //    Move a userItem around the appropriate button.
  556. //    
  557. //    This function should be used in conjunction with
  558. //    InstallDefaultOutline to move the default button indicator
  559. //    from one button to another.  If you are using the
  560. //    CutPasteFilter with this routine, Return and Enter will
  561. //    automatically be translated to the correct button
  562. //----------------------------------------------------------------------------------------
  563. void MoveOutline(DialogPtr dlog, short userItem, short button)
  564. {
  565.     short            type;
  566.     Handle            item;
  567.     Rect            newBox;
  568.     Rect            oldBox;
  569.     
  570.     GetDItem(dlog, ((DialogPeek)dlog)->aDefItem, &type, &item, &oldBox);
  571.     InsetRect(&oldBox,-4,-4);
  572.     GetDItem(dlog, button, &type, &item, &newBox);
  573.     InsetRect(&newBox,-4,-4);
  574.     
  575.     //
  576.     // Erase the old box & invalidate the old and new
  577.     // locations to force a redraw
  578.     //
  579.     EraseRect( &oldBox );
  580.     InvalRect( &oldBox );
  581.     InvalRect( &newBox );
  582.     
  583.     //
  584.     // Remember where the default button outline moved to
  585.     //
  586.     ((DialogPeek)dlog)->aDefItem = button;
  587. } // MoveOutline 
  588.  
  589. //----------------------------------------------------------------------------------------
  590. // MoveActiveIndicator: 
  591. //    
  592. //    Move the active item indicator to another item.
  593. //    
  594. //    Note:    This routine erases and redraws the active item.
  595. //            It would be better to erase & invalidate, but that's
  596. //            pretty slow.
  597. //----------------------------------------------------------------------------------------
  598. void MoveActiveIndicator(DialogPtr dlog, short userItem, short button)
  599. {
  600.     short            type;
  601.     Handle            item;
  602.     Rect            box;
  603.     Rect            userBox;
  604.     RgnHandle        badRgn;
  605.     RgnHandle        tmpRgn;
  606.     
  607.     GetDItem(dlog, button, &type, &item, &box);
  608.     InsetRect(&box,-4,-4);
  609.     GetDItem(dlog, userItem, &type, &item, &userBox);
  610.     SetDItem(dlog, userItem, type, item, &box );
  611.     
  612.     //
  613.     // Erase the old active item indicator
  614.     //
  615.     badRgn = NewRgn();
  616.     tmpRgn = NewRgn();
  617.     RectRgn( badRgn, &userBox );
  618.     InsetRect( &userBox, 2, 2 );
  619.     RectRgn( tmpRgn, &userBox );
  620.     DiffRgn( badRgn, tmpRgn, badRgn );
  621.     EraseRgn( badRgn );
  622.     InvalRgn( badRgn );
  623.     DisposeRgn( badRgn );
  624.     DisposeRgn( tmpRgn );
  625.     
  626.     //
  627.     // Draw the new one
  628.     //
  629.     DrawActiveItemProc( dlog, userItem );
  630. } // MoveActiveIndicator 
  631.  
  632. //----------------------------------------------------------------------------------------
  633. // MoveDItem: 
  634. //    
  635. //    Move a Dialog Item.
  636. //    
  637. //    This is not _quite_ as easy as it sounds, because if the item
  638. //    is a control (such as a check box or radio button), MoveControl
  639. //    must also be called.
  640. //    
  641. //    NOTE:    This routine doesn't quite work, because it does not
  642. //            erase or redraw the item that moved unless it is
  643. //            a control.  Tsk tsk.
  644. //----------------------------------------------------------------------------------------
  645. void MoveDItem( DialogPtr dlog, short itemNumber, short h, short v )
  646. {
  647.     Handle            itemHandle;
  648.     short            itemType;
  649.     Rect            box;
  650.     
  651.     //
  652.     // Get some useful information about the DItem to move
  653.     //
  654.     GetDItem( dlog, itemNumber, &itemType, (Handle*)&itemHandle, &box );
  655.     
  656.     //
  657.     // Move the bounding box to the correct location
  658.     //
  659.     box.bottom += (v - box.top);
  660.     box.right += (h - box.left);
  661.     box.top = v;
  662.     box.left = h;
  663.     
  664.     //
  665.     // Set the bounding box of the item to move
  666.     //
  667.     SetDItem( dlog, itemNumber, itemType, (Handle)itemHandle, &box );
  668.     
  669.     //
  670.     // If the item is a control, call MoveControl
  671.     //
  672.     if( (itemType & ctrlItem) != 0 )
  673.     {
  674.         MoveControl( (ControlHandle)itemHandle, h, v );
  675.     }
  676. } // MoveDItem 
  677.  
  678. //----------------------------------------------------------------------------------------
  679. // SetItemHandle: 
  680. //    
  681. //    Set the item handle of a dialog item (particularly useful for
  682. //    useritems)
  683. //----------------------------------------------------------------------------------------
  684. void SetItemHandle( DialogPtr dlog, short whichItem, Handle newItem )
  685. {
  686.     short            type;
  687.     Handle            itemHandle;
  688.     Rect            box;
  689.     
  690.     GetDItem(dlog,whichItem,&type,&itemHandle,&box);
  691.     SetDItem(dlog,whichItem,type,newItem,&box);
  692. } // SetItemHandle 
  693.  
  694. //----------------------------------------------------------------------------------------
  695. // GetItemPoint: 
  696. //
  697. //    Returns the location of a given dialog item
  698. //----------------------------------------------------------------------------------------
  699. Point GetItemPoint( DialogPtr dlog, short itemNum )
  700. {
  701.     Point        loc;
  702.     short        type;
  703.     Handle        item;
  704.     Rect        box;
  705.     
  706.     GetDItem(dlog,itemNum, &type, &item, &box);
  707.     loc.h = box.left;
  708.     loc.v = box.top;
  709.     return( loc );
  710. } // GetItemPoint 
  711.  
  712. //----------------------------------------------------------------------------------------
  713. // DialogItemEnabled: 
  714. //    
  715. //    This routine is used by DrawDefaultProc and CutPasteFilter
  716. //    to determine if the default button is enabled
  717. //----------------------------------------------------------------------------------------
  718. Boolean DialogItemEnabled(DialogPtr dlog, short item)
  719. {
  720.     ControlHandle        buttonHandle = nil;
  721.     Rect                buttonBox;
  722.     short                type;
  723.  
  724.     GetDItem(dlog, item, &type, (Handle*)&buttonHandle, &buttonBox);
  725.     return ((type & itemDisable) == false);
  726. } // DialogItemEnabled 
  727.  
  728. //----------------------------------------------------------------------------------------
  729. // SetDialogItemDisableBit: 
  730. //
  731. //    Set or clear the 'itemDisable' bit of the dialog item
  732. //----------------------------------------------------------------------------------------
  733. void SetDialogItemDisableBit(DialogPtr dlog, short item, Boolean enable)
  734. {
  735.     Handle                itemHandle;
  736.     short                itemType;
  737.     Rect                box;
  738.     
  739.     GetDItem(dlog,item,&itemType,&itemHandle,&box);
  740.     itemType = (itemType & ~itemDisable) + (enable ? 0 : itemDisable);
  741.     SetDItem(dlog,item,itemType,itemHandle,&box);
  742. } // SetDialogItemDisableBit 
  743.  
  744. //----------------------------------------------------------------------------------------
  745. // EnableButton: 
  746. //
  747. //    This simple routine will enable or disable a button
  748. //----------------------------------------------------------------------------------------
  749. void EnableButton(DialogPtr dlog, short button,Boolean enable)
  750. {
  751.     ControlHandle        buttonHandle;
  752.     short                type;
  753.     Rect                box;
  754.     
  755.     SetDialogItemDisableBit(dlog, button, enable);
  756.     GetDItem(dlog,button,&type,(Handle*)&buttonHandle,&box);
  757.     HiliteControl(buttonHandle, enable ? 0 : 255);
  758.  
  759.     //
  760.     // Special checking:  are we enabling/disabling the
  761.     // default button?  If so, invalidate the area around
  762.     // the button so the default outline will redraw
  763.     //
  764.     if(button == ((DialogPeek)dlog)->aDefItem)
  765.     {
  766.         InsetRect(&box, -6, -6);
  767.         InvalRect(&box);
  768.     }
  769. } // EnableButton 
  770.  
  771. //----------------------------------------------------------------------------------------
  772. // EnabledTEItemsExist: 
  773. //
  774. //    Return true if there is at least one enabled TE item
  775. //----------------------------------------------------------------------------------------
  776. Boolean EnabledTEItemsExist(DialogPtr dlog)
  777. {
  778.     Boolean enabledTEExists = false;
  779.     short i;
  780.     
  781.     for(i=1; i < (**((short**)(((DialogPeek)dlog)->items)) + 1); ++i)
  782.     {
  783.         Handle                itemHandle;
  784.         short                itemType;
  785.         Rect                box;
  786.         
  787.         GetDItem(dlog,i,&itemType,&itemHandle,&box);
  788.         if(((itemType & itemDisable) == 0) && ((itemType & editText) == editText))
  789.             enabledTEExists = true;
  790.     }
  791.     
  792.     return enabledTEExists;
  793. }
  794.  
  795. //----------------------------------------------------------------------------------------
  796. // FindNextEnabledTEItem: 
  797. //
  798. //    Return the item # of the next enabled EditText item.
  799. //----------------------------------------------------------------------------------------
  800. short FindNextEnabledTEItem(DialogPtr dlog, short item)
  801. {
  802.     short searchFrom = item + 1;
  803.     short terminate = 0;
  804.     short itemFound = 0;
  805.     
  806.     //
  807.     // Look at every item in the list except for 'item'
  808.     //
  809.     while((searchFrom != item) && (searchFrom != terminate))
  810.     {
  811.         Handle                itemHandle;
  812.         short                itemType;
  813.         Rect                box;
  814.         
  815.         //
  816.         // When we get to the end, wrap around.  Set 'terminate'
  817.         // just in case 'item' has a bogus value
  818.         //
  819.         if(searchFrom > (**((short**)(((DialogPeek)dlog)->items)) + 1))
  820.         {
  821.             terminate = searchFrom;
  822.             searchFrom = 1;
  823.         }
  824.         
  825.         //
  826.         // Is this item an enabled textEdit item?
  827.         //
  828.         GetDItem(dlog,searchFrom,&itemType,&itemHandle,&box);
  829.         if(((itemType & itemDisable) == 0) && ((itemType & editText) == editText))
  830.         {
  831.             itemFound = searchFrom;
  832.             break;
  833.         }
  834.         ++searchFrom;
  835.     }
  836.     
  837.     return itemFound;
  838. }
  839.  
  840. //----------------------------------------------------------------------------------------
  841. // TabToNextEnabledTEItem: 
  842. //
  843. //    The dialog manager does not respect disabled TE items, so we need to have our
  844. //    own method of skipping to the next item when tab is pressed.
  845. //----------------------------------------------------------------------------------------
  846. void TabToNextEnabledTEItem(DialogPtr dlog)
  847. {
  848.     short itemToTabTo = FindNextEnabledTEItem(dlog, ((DialogPeek)dlog)->editField + 1);
  849.     if(itemToTabTo > 0)
  850.     {
  851.         SelIText(dlog, itemToTabTo, 0, 32767);
  852.     }
  853. }
  854.  
  855. //----------------------------------------------------------------------------------------
  856. // EnableTEItem: 
  857. //
  858. //    I wish this worked without extra support, but the dialog manager does not
  859. //    respect disabled editText items.  We have some convoluted code here that works
  860. //    in conjunction with the modless dialog handler code in the Window handler that
  861. //    allows us to disable editText items.
  862. //----------------------------------------------------------------------------------------
  863. void EnableTEItem(DialogPtr dlog, short item, Boolean enable)
  864. {
  865.     Handle                itemHandle;
  866.     short                itemType;
  867.     Rect                box;
  868.     
  869.     //
  870.     // First check to see if the TE item is going from
  871.     // enabled to disabled
  872.     //
  873.     GetDItem(dlog,item,&itemType,&itemHandle,&box);
  874.     if((enable == false) && ((itemType & itemDisable) == 0))
  875.     {
  876.         //
  877.         // Is this item the active TE item?
  878.         //
  879.         if(((DialogPeek)dlog)->editField == item - 1)
  880.         {
  881.             //
  882.             // Find an enabled editText item
  883.             //
  884.             short anEnabledItem = FindNextEnabledTEItem(dlog, item);
  885.             if(anEnabledItem == 0)
  886.             {
  887.                 //
  888.                 // Time to disable the last TE item
  889.                 //
  890.                 SelIText(dlog, item, 0, 0);
  891.                 TEDeactivate(((DialogPeek)dlog)->textH);
  892.             }
  893.             else
  894.             {
  895.                 //
  896.                 // I hope that this will activate the item whose
  897.                 // text is being selected, and deactivate 'item'
  898.                 //
  899.                 SelIText(dlog, anEnabledItem, 0, 32767);
  900.             }
  901.         }
  902.     }
  903.     
  904.     //
  905.     // Invalidate the area around the TE item in case
  906.     // InstallGreyTransform was called on a userItem
  907.     // around it.
  908.     // 
  909.     InsetRect(&box, -6, -6);
  910.     InvalRect(&box);
  911.     SetDialogItemDisableBit(dlog, item, enable);
  912.  
  913.     //
  914.     // We also have some work to do when enabling the first
  915.     // TE item (since we called TEDeactivate when we disable
  916.     // the last item, we'd better call TEActivate when we
  917.     // enable it)
  918.     //
  919.     if((enable == true) && ((itemType & itemDisable) != 0))
  920.     {
  921.         //
  922.         // If there is an enabled item somewhere, we don't
  923.         // have to worry about calling TEActivate because
  924.         // we did not call TEDeactivate.
  925.         //
  926.         if(FindNextEnabledTEItem(dlog, item) == 0)
  927.         {
  928.             //
  929.             // Fortunately, we don't need to worry about
  930.             // the fact that we may have disabled a
  931.             // "different" editText item, because there
  932.             // is only one TEHandle that is shared among
  933.             // all editable items.
  934.             // 
  935.             TEActivate(((DialogPeek)dlog)->textH);
  936.             SelIText(dlog, item, 0, 32767);
  937.         }
  938.     }
  939. } // EnableTEItem 
  940.  
  941. //----------------------------------------------------------------------------------------
  942. // GetCheckboxState: 
  943. //    
  944. //    Returns true of the checkbox is checked
  945. //----------------------------------------------------------------------------------------
  946. Boolean GetCheckboxState(DialogPtr dlog, short checkbox)
  947. {
  948.     Boolean state = false;
  949.     short itemType;
  950.     ControlHandle checkboxControl;
  951.     Rect box;
  952.     
  953.     GetDItem(dlog, checkbox, &itemType, (Handle*)&checkboxControl, &box);
  954.     if((itemType & (chkCtrl + ctrlItem)) == chkCtrl + ctrlItem)
  955.     {
  956.         state = GetCtlValue(checkboxControl);
  957.     }
  958.     
  959.     return state;
  960. } // GetCheckboxState 
  961.  
  962. //----------------------------------------------------------------------------------------
  963. // SetCheckboxState: 
  964. //    
  965. //    Check or uncheck a button
  966. //----------------------------------------------------------------------------------------
  967. void SetCheckboxState(DialogPtr dlog, short checkbox, Boolean check)
  968. {
  969.     short itemType;
  970.     ControlHandle checkboxControl;
  971.     Rect box;
  972.     
  973.     GetDItem(dlog, checkbox, &itemType, (Handle*)&checkboxControl, &box);
  974.     if((itemType & (chkCtrl + ctrlItem)) == chkCtrl + ctrlItem)
  975.     {
  976.         SetCtlValue(checkboxControl, check);
  977.     }
  978. } // SetCheckboxState 
  979.  
  980. //----------------------------------------------------------------------------------------
  981. // ToggleCheckboxState: 
  982. //    
  983. //    Reverse the state of a checkbox
  984. //----------------------------------------------------------------------------------------
  985. void ToggleCheckboxState(DialogPtr dlog, short checkbox)
  986. {
  987.     SetCheckboxState(dlog, checkbox, !GetCheckboxState(dlog, checkbox));
  988. } // ToggleCheckboxState 
  989.  
  990. //----------------------------------------------------------------------------------------
  991. // FlashDlogItem: 
  992. //    
  993. //    Momentarily hilite a dialog button
  994. //----------------------------------------------------------------------------------------
  995. void FlashDlogItem( DialogPtr dlog, short itemNum )
  996. {
  997.     Handle        itemHandle;
  998.     short        itemType;
  999.     Rect        iRect;
  1000.     long        ticky;
  1001.     
  1002.     GetDItem(dlog,itemNum,&itemType,&itemHandle,&iRect);
  1003.     HiliteControl((ControlHandle)itemHandle,1);
  1004.     Draw1Control((ControlHandle)itemHandle);
  1005.     ticky = TickCount() + 10;
  1006.     do {} while( ticky > TickCount() );
  1007.     HiliteControl((ControlHandle)itemHandle,0);
  1008.     Draw1Control((ControlHandle)itemHandle);
  1009. } // FlashDlogItem 
  1010.  
  1011. //----------------------------------------------------------------------------------------
  1012. // CutPasteFilter: 
  1013. //    
  1014. //    This filter, when passed to ModalDialog, will allow the user to
  1015. //    cut, copy and paste by pressing command-X, command-C or command-V,
  1016. //    respectively.  It also checks if the cursor is over an editText
  1017. //    item, and if so, the cursor is changed into an IBeam.
  1018. //    
  1019. //    This procedure may be used as the filterProc of any dialog that
  1020. //    uses ModelDialog().  Note that this filter calls FlashDlogItem(),
  1021. //    above.  In all other respects, it is completely self-contained.
  1022. //    
  1023. //    This routine always translates command-. to button #2.
  1024. //    Your dialog box should have button #2 set up as a
  1025. //    'Cancel' button if you use this routine.
  1026. //----------------------------------------------------------------------------------------
  1027. pascal Boolean CutPasteFilter( DialogPtr dlog, EventRecord* event, short* item )
  1028. {
  1029.     DialogRecord    *dp = (DialogRecord *)dlog;
  1030.     TEHandle        te;
  1031.     Str255            Pstr;
  1032.     long            num;
  1033.     char            key;
  1034.     char            code;
  1035.     short            itemType = statText;
  1036.     short            itemNum;
  1037.     Handle            itemHandle;
  1038.     Point            mouse;
  1039.     Rect            tRect;
  1040.     
  1041.     te = dp->textH;
  1042.     
  1043.     //
  1044.     // Adjust the cursor to an iBeam or Arrow as appropriate
  1045.     //    
  1046.     GetMouse( &mouse );
  1047.     itemNum = FindDItem(dlog,mouse) + 1;
  1048.     if( itemNum > 0 )
  1049.         GetDItem(dlog,itemNum,&itemType,&itemHandle,&tRect);
  1050.     SetCursor( (itemType == editText) ? *GetCursor(iBeamCursor) : &qd.arrow);
  1051.     
  1052.     //
  1053.     // If the event is an update event, check to see
  1054.     // if it is for this dialog or for some other window
  1055.     //
  1056.     if( (event->what == updateEvt) )
  1057.     {
  1058.         //
  1059.         // If the update event is for this dialog box,
  1060.         // then draw the default button
  1061.         //
  1062.         if( StripAddress((DialogPtr)event->message) == StripAddress(dlog) )
  1063.         {
  1064.             //
  1065.             // The 'item' parameter is ignored, but we
  1066.             // don't have any better value to pass to
  1067.             // it than the item # of the default button
  1068.             //
  1069.             DrawDefaultProc(dlog, ((DialogPeek)dlog)->aDefItem );
  1070.         }
  1071.     }
  1072.     
  1073.     //
  1074.     // Is the event a key-down event?
  1075.     //
  1076.     if( (event->what == keyDown) || (event->what == autoKey) )
  1077.     {
  1078.         key  = (event->message & charCodeMask);
  1079.         code = (event->message &  keyCodeMask) >> 8;
  1080.         
  1081.         //
  1082.         // If F2, F3 or F4 (cut, copy or paste) are pressed,
  1083.         // forge a Command-X, C or V and handle the appropriate
  1084.         // command below.
  1085.         //
  1086.         switch( code )
  1087.         {
  1088.             case 120:
  1089.             {
  1090.                 event->modifiers |= cmdKey;
  1091.                 key = 'x';
  1092.                 break;
  1093.             }
  1094.             
  1095.             case  99:
  1096.             {
  1097.                 event->modifiers |= cmdKey;
  1098.                 key = 'c';
  1099.                 break;
  1100.             }
  1101.             
  1102.             case 118:
  1103.             {
  1104.                 event->modifiers |= cmdKey;
  1105.                 key = 'v';
  1106.                 break;
  1107.             }
  1108.         }
  1109.         
  1110.         //
  1111.         // Is the command key down?
  1112.         //
  1113.         if( event->modifiers & cmdKey )
  1114.         {
  1115.             switch( key )
  1116.             {
  1117.                 //
  1118.                 // Command-X, C and V are cut, copy and paste.
  1119.                 //
  1120.                 case 'x':
  1121.                 case 'c':
  1122.                 {
  1123.                     ZeroScrap();
  1124.                     if( key == 'x' )
  1125.                         DlgCut( dlog );
  1126.                     else
  1127.                         DlgCopy( dlog );
  1128.                     if( TEToScrap() != noErr )
  1129.                         SysBeep(120);
  1130.                     return true;
  1131.                 }
  1132.                                         
  1133.                 case 'v':
  1134.                 {
  1135.                     if( TEFromScrap() == noErr )
  1136.                         DlgPaste( dlog );
  1137.                     else
  1138.                         SysBeep(120);
  1139.                     return true;
  1140.                 }
  1141.                 
  1142.                 //
  1143.                 // Command-. cancels
  1144.                 //
  1145.                 case '.':
  1146.                 {
  1147.                     *item = 2;
  1148.                     FlashDlogItem( dlog, *item );
  1149.                     return true;
  1150.                 }
  1151.             }
  1152.             
  1153.             //
  1154.             // All other command-key combinations do nothing
  1155.             //
  1156.             event->what = nullEvent;
  1157.             return false;
  1158.         }
  1159.         
  1160.         //
  1161.         // If RETURN or ENTER was pressed, exit with
  1162.         // itemHit = ((DialogPeek)dlog)->aDefItem--but only if the
  1163.         // default button is enabled.
  1164.         //
  1165.         if( ((key == 13) || (key == 3)) && DialogItemEnabled(dlog,((DialogPeek)dlog)->aDefItem) )
  1166.         {
  1167.             *item = ((DialogPeek)dlog)->aDefItem;
  1168.             FlashDlogItem( dlog, *item );
  1169.             return true;
  1170.         }
  1171.         
  1172.         //
  1173.         // Swallow non-printing characters
  1174.         //
  1175.         if( (key < ' ') && (key != 8) && (key != 9) )
  1176.         {
  1177.             event->what = nullEvent;
  1178.             return false;
  1179.         }
  1180.     }
  1181.     return false;
  1182. } // CutPasteFilter 
  1183.